package com.hui.security.plugin;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.util.Properties;

/**
 * <b><code>DataRulePlugin</code></b>
 * <p/>
 * Description: 行级数据权限
 * <p/>
 * <b>Creation Time:</b> 2019/1/13 1:05.
 *
 * @author HuWeihui
 */
/*@Intercepts({
        @Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class})
})
@Component*/
@Slf4j
public class DataRuleRowPlugin implements Interceptor {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 拦截目标对象中目标方法的执行
     * 是我们拦截到对象后所进行操作的位置，也就是我们之后编写逻辑代码的位置。
     * @param invocation the invocation
     * @return the object
     * @throws Throwable the throwable
     * @author HuWeihui
     * @since hui_project v1
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("进入数据权限 PrepareInterceptor  拦截器");
        if (invocation.getTarget() instanceof RoutingStatementHandler){

            RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();

            //反射获取属性值里面的 StatementHandler delegate
            Field delegateField = ReflectionUtils.findField(RoutingStatementHandler.class, "delegate");

            if (null!=delegateField){
                delegateField.setAccessible(true);
            }

            StatementHandler delegate = (StatementHandler) delegateField.get(handler);

            //获取Mapper 用于注解判断
            Field mappedStatementField = ReflectionUtils.findField(StatementHandler.class, "mappedStatement");

            if(null!=mappedStatementField){
                mappedStatementField.setAccessible(true);

                MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(delegate);


            }

            //获取sql
            BoundSql boundSql = delegate.getBoundSql();

            Field sqlField = ReflectionUtils.findField(BoundSql.class, "sql");

            if (null != sqlField){

                sqlField.setAccessible(true);

                //todo RestTemplate 查询API返回数据规则


                sqlField.set(boundSql,boundSql + " and 1=1 ");

            }

        }
        return invocation.proceed();
    }

    /**
     * 包装目标对象,即为目标对象创建一个代理对象
     * 根据参数可以看出，该方法的作用是拦截我们需要拦截到的对象。
     * @param target the target
     * @return the object
     * @author HuWeihui
     * @since hui_project v1
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }

    /**
     * 可以获取插件注册时,传入的property属性
     * 我们可以通过配置文件中进行properties配置,然后在该方法中读取到配置。
     * @param properties the properties
     * @author HuWeihui
     * @since hui_project v1
     */
    @Override
    public void setProperties(Properties properties) {

    }
}
